﻿using System.Diagnostics;

namespace Devonline.Core;

/// <summary>
/// 委托相关扩展方法
/// </summary>
public static class DelegateExtensions
{
    /// <summary>
    /// 执行方法并返回执行时间
    /// </summary>
    /// <param name="action"></param>
    /// <returns></returns>
    public static TimeSpan WatchAction(this Action action)
    {
        if (action == null)
        {
            throw new ArgumentNullException(nameof(action));
        }

        Stopwatch watch = Stopwatch.StartNew();
        action();
        return watch.Elapsed;
    }
    /// <summary>
    /// 执行方法并返回执行时间
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="action"></param>
    /// <param name="t"></param>
    /// <returns></returns>
    public static TimeSpan WatchAction<T>(this Action<T> action, T t)
    {
        if (action == null)
        {
            throw new ArgumentNullException(nameof(action));
        }

        Stopwatch watch = Stopwatch.StartNew();
        action(t);
        return watch.Elapsed;
    }
    /// <summary>
    /// 执行任务并返回执行时间
    /// </summary>
    /// <param name="exec"></param>
    /// <returns></returns>
    public static async Task<TimeSpan> WatchActionAsync(this Func<Task> task)
    {
        ArgumentNullException.ThrowIfNull(task);
        var watch = Stopwatch.StartNew();
        await task().ConfigureAwait(false);
        return watch.Elapsed;
    }
    /// <summary>
    /// 执行任务并返回执行时间
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="task"></param>
    /// <param name="t"></param>
    /// <returns></returns>
    public static async Task<TimeSpan> WatchActionAsync<T>(this Func<T, Task> task, T t)
    {
        ArgumentNullException.ThrowIfNull(task);
        Stopwatch watch = Stopwatch.StartNew();
        await task(t).ConfigureAwait(true);
        return watch.Elapsed;
    }

    /// <summary>
    /// 自动按循环条件执行任务
    /// </summary>
    /// <param name="task">要执行的主任务</param>
    /// <param name="loopCondition">循环条件</param>
    /// <param name="whenException">循环期间发生异常时执行的方法委托</param>
    /// <param name="whenFinally">循环期间, 每一轮执行完成后的处理方法委托, 默认线程休眠 1s</param>
    /// <returns></returns>
    public static bool Execute(this Func<bool> task, Func<bool> loopCondition, Action<Exception>? whenException = null, Action<bool>? whenFinally = null)
    {
        var result = false;
        while (loopCondition() && !result)
        {
            try
            {
                result = task();
            }
            catch (Exception ex)
            {
                whenException?.Invoke(ex);
            }
            finally
            {
                if (whenFinally == null)
                {
                    Thread.Sleep(AppSettings.UNIT_THOUSAND);
                }
                else
                {
                    whenFinally(result);
                }
            }
        }

        return result;
    }
    /// <summary>
    /// 自动按循环条件执行任务
    /// </summary>
    /// <param name="task">要执行的主任务</param>
    /// <param name="loopCondition">循环条件</param>
    /// <param name="whenException">循环期间发生异常时执行的方法委托</param>
    /// <param name="whenFinally">循环期间, 每一轮执行完成后的处理方法委托, 默认线程休眠 1s</param>
    /// <returns></returns>
    public static async Task<bool> ExecuteAsync(this Func<Task<bool>> task, Func<bool> loopCondition, Action<Exception>? whenException = null, Action<bool>? whenFinally = null)
    {
        var result = false;
        while (loopCondition() && !result)
        {
            try
            {
                result = await task().ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                whenException?.Invoke(ex);
            }
            finally
            {
                if (whenFinally == null)
                {
                    Thread.Sleep(AppSettings.UNIT_THOUSAND);
                }
                else
                {
                    whenFinally(result);
                }
            }
        }

        return result;
    }
}